blob: 56cc5d48f4f983f47faa48f2a28affc458887b41 [file] [log] [blame]
Tom Rini8b0c8a12018-05-06 18:27:01 -04001/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
Simon Glassa13d9022017-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 Glassa13d9022017-05-27 07:38:11 -06006 */
7
8%module libfdt
9
Michal Suchanek96c2ead2022-10-13 22:43:41 +020010%begin %{
11#define PY_SSIZE_T_CLEAN
12%}
13
Simon Glass1c879312017-08-13 16:02:54 -060014%include <stdint.i>
15
Simon Glassa13d9022017-05-27 07:38:11 -060016%{
17#define SWIG_FILE_WITH_INIT
18#include "libfdt.h"
Simon Glass70cd0d72018-07-06 10:27:20 -060019
20/*
21 * We rename this function here to avoid problems with swig, since we also have
22 * a struct called fdt_property. That struct causes swig to create a class in
23 * libfdt.py called fdt_property(), which confuses things.
24 */
Simon Glassc5db5192019-10-31 07:43:01 -060025static int fdt_property_stub(void *fdt, const char *name, const void *val,
Simon Glassb474c762018-07-26 14:02:13 -060026 int len)
Simon Glass70cd0d72018-07-06 10:27:20 -060027{
28 return fdt_property(fdt, name, val, len);
29}
30
Simon Glassa13d9022017-05-27 07:38:11 -060031%}
32
33%pythoncode %{
34
35import struct
36
37# Error codes, corresponding to FDT_ERR_... in libfdt.h
38(NOTFOUND,
39 EXISTS,
40 NOSPACE,
41 BADOFFSET,
42 BADPATH,
43 BADPHANDLE,
44 BADSTATE,
45 TRUNCATED,
46 BADMAGIC,
47 BADVERSION,
48 BADSTRUCTURE,
49 BADLAYOUT,
50 INTERNAL,
51 BADNCELLS,
52 BADVALUE,
53 BADOVERLAY,
54 NOPHANDLES) = QUIET_ALL = range(1, 18)
55# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
56# altogether. All # functions passed this value will return an error instead
57# of raising an exception.
58
59# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
60# instead of raising an exception.
61QUIET_NOTFOUND = (NOTFOUND,)
Simon Glassb474c762018-07-26 14:02:13 -060062QUIET_NOSPACE = (NOSPACE,)
Simon Glassa13d9022017-05-27 07:38:11 -060063
64
65class FdtException(Exception):
66 """An exception caused by an error such as one of the codes above"""
67 def __init__(self, err):
68 self.err = err
69
70 def __str__(self):
71 return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
72
73def strerror(fdt_err):
74 """Get the string for an error number
75
76 Args:
77 fdt_err: Error number (-ve)
78
79 Returns:
80 String containing the associated error
81 """
82 return fdt_strerror(fdt_err)
83
84def check_err(val, quiet=()):
85 """Raise an error if the return value is -ve
86
87 This is used to check for errors returned by libfdt C functions.
88
89 Args:
90 val: Return value from a libfdt function
91 quiet: Errors to ignore (empty to raise on all errors)
92
93 Returns:
94 val if val >= 0
95
96 Raises
97 FdtException if val < 0
98 """
Simon Glassfd926662019-10-31 07:43:00 -060099 if isinstance(val, int) and val < 0:
Simon Glassa13d9022017-05-27 07:38:11 -0600100 if -val not in quiet:
101 raise FdtException(val)
102 return val
103
104def check_err_null(val, quiet=()):
105 """Raise an error if the return value is NULL
106
107 This is used to check for a NULL return value from certain libfdt C
108 functions
109
110 Args:
111 val: Return value from a libfdt function
112 quiet: Errors to ignore (empty to raise on all errors)
113
114 Returns:
115 val if val is a list, None if not
116
117 Raises
118 FdtException if val indicates an error was reported and the error
119 is not in @quiet.
120 """
121 # Normally a list is returned which contains the data and its length.
122 # If we get just an integer error code, it means the function failed.
123 if not isinstance(val, list):
124 if -val not in quiet:
125 raise FdtException(val)
126 return val
127
Simon Glassb474c762018-07-26 14:02:13 -0600128class FdtRo(object):
129 """Class for a read-only device-tree
Simon Glass70cd0d72018-07-06 10:27:20 -0600130
Simon Glassb474c762018-07-26 14:02:13 -0600131 This is a base class used by FdtRw (read-write access) and FdtSw
132 (sequential-write access). It implements read-only access to the
133 device tree.
Simon Glassa13d9022017-05-27 07:38:11 -0600134
Simon Glassb474c762018-07-26 14:02:13 -0600135 Here are the three classes and when you should use them:
Simon Glassa13d9022017-05-27 07:38:11 -0600136
Simon Glassb474c762018-07-26 14:02:13 -0600137 FdtRo - read-only access to an existing FDT
138 FdtRw - read-write access to an existing FDT (most common case)
139 FdtSw - for creating a new FDT, as well as allowing read-only access
Simon Glassa13d9022017-05-27 07:38:11 -0600140 """
141 def __init__(self, data):
142 self._fdt = bytearray(data)
143 check_err(fdt_check_header(self._fdt));
144
Simon Glass70cd0d72018-07-06 10:27:20 -0600145 def as_bytearray(self):
146 """Get the device tree contents as a bytearray
147
148 This can be passed directly to libfdt functions that access a
149 const void * for the device tree.
150
151 Returns:
152 bytearray containing the device tree
153 """
154 return bytearray(self._fdt)
155
156 def next_node(self, nodeoffset, depth, quiet=()):
157 """Find the next subnode
158
159 Args:
160 nodeoffset: Node offset of previous node
Simon Glassb474c762018-07-26 14:02:13 -0600161 depth: The depth of the node at nodeoffset. This is used to
162 calculate the depth of the returned node
Simon Glass70cd0d72018-07-06 10:27:20 -0600163 quiet: Errors to ignore (empty to raise on all errors)
164
165 Returns:
Simon Glassb474c762018-07-26 14:02:13 -0600166 Typle:
167 Offset of the next node, if any, else a -ve error
168 Depth of the returned node, if any, else undefined
Simon Glass70cd0d72018-07-06 10:27:20 -0600169
170 Raises:
171 FdtException if no more nodes found or other error occurs
172 """
173 return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
174
175 def first_subnode(self, nodeoffset, quiet=()):
176 """Find the first subnode of a parent node
177
178 Args:
179 nodeoffset: Node offset of parent node
180 quiet: Errors to ignore (empty to raise on all errors)
181
182 Returns:
183 The offset of the first subnode, if any
184
185 Raises:
186 FdtException if no subnodes found or other error occurs
187 """
188 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
189
190 def next_subnode(self, nodeoffset, quiet=()):
191 """Find the next subnode
192
193 Args:
194 nodeoffset: Node offset of previous subnode
195 quiet: Errors to ignore (empty to raise on all errors)
196
197 Returns:
198 The offset of the next subnode, if any
199
200 Raises:
201 FdtException if no more subnodes found or other error occurs
202 """
203 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
204
205 def magic(self):
206 """Return the magic word from the header
207
208 Returns:
209 Magic word
210 """
Simon Glassb474c762018-07-26 14:02:13 -0600211 return fdt_magic(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600212
213 def totalsize(self):
214 """Return the total size of the device tree
215
216 Returns:
217 Total tree size in bytes
218 """
Simon Glassb474c762018-07-26 14:02:13 -0600219 return fdt_totalsize(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600220
221 def off_dt_struct(self):
222 """Return the start of the device-tree struct area
223
224 Returns:
225 Start offset of struct area
226 """
Simon Glassb474c762018-07-26 14:02:13 -0600227 return fdt_off_dt_struct(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600228
229 def off_dt_strings(self):
230 """Return the start of the device-tree string area
231
232 Returns:
233 Start offset of string area
234 """
Simon Glassb474c762018-07-26 14:02:13 -0600235 return fdt_off_dt_strings(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600236
237 def off_mem_rsvmap(self):
238 """Return the start of the memory reserve map
239
240 Returns:
241 Start offset of memory reserve map
242 """
Simon Glassb474c762018-07-26 14:02:13 -0600243 return fdt_off_mem_rsvmap(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600244
245 def version(self):
246 """Return the version of the device tree
247
248 Returns:
249 Version number of the device tree
250 """
Simon Glassb474c762018-07-26 14:02:13 -0600251 return fdt_version(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600252
253 def last_comp_version(self):
254 """Return the last compatible version of the device tree
255
256 Returns:
257 Last compatible version number of the device tree
258 """
Simon Glassb474c762018-07-26 14:02:13 -0600259 return fdt_last_comp_version(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600260
261 def boot_cpuid_phys(self):
262 """Return the physical boot CPU ID
263
264 Returns:
265 Physical boot CPU ID
266 """
Simon Glassb474c762018-07-26 14:02:13 -0600267 return fdt_boot_cpuid_phys(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600268
269 def size_dt_strings(self):
270 """Return the start of the device-tree string area
271
272 Returns:
273 Start offset of string area
274 """
Simon Glassb474c762018-07-26 14:02:13 -0600275 return fdt_size_dt_strings(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600276
277 def size_dt_struct(self):
278 """Return the start of the device-tree struct area
279
280 Returns:
281 Start offset of struct area
282 """
Simon Glassb474c762018-07-26 14:02:13 -0600283 return fdt_size_dt_struct(self._fdt)
Simon Glass70cd0d72018-07-06 10:27:20 -0600284
285 def num_mem_rsv(self, quiet=()):
286 """Return the number of memory reserve-map records
287
288 Returns:
289 Number of memory reserve-map records
290 """
291 return check_err(fdt_num_mem_rsv(self._fdt), quiet)
292
293 def get_mem_rsv(self, index, quiet=()):
294 """Return the indexed memory reserve-map record
295
296 Args:
297 index: Record to return (0=first)
298
299 Returns:
300 Number of memory reserve-map records
301 """
302 return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
303
Simon Glass460b2522017-08-29 14:15:46 -0600304 def subnode_offset(self, parentoffset, name, quiet=()):
305 """Get the offset of a named subnode
306
307 Args:
308 parentoffset: Offset of the parent node to check
309 name: Name of the required subnode, e.g. 'subnode@1'
310 quiet: Errors to ignore (empty to raise on all errors)
311
312 Returns:
313 The node offset of the found node, if any
314
315 Raises
316 FdtException if there is no node with that name, or other error
317 """
318 return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
319 quiet)
320
Simon Glassa13d9022017-05-27 07:38:11 -0600321 def path_offset(self, path, quiet=()):
322 """Get the offset for a given path
323
324 Args:
325 path: Path to the required node, e.g. '/node@3/subnode@1'
326 quiet: Errors to ignore (empty to raise on all errors)
327
328 Returns:
329 Node offset
330
331 Raises
332 FdtException if the path is not valid or not found
333 """
334 return check_err(fdt_path_offset(self._fdt, path), quiet)
335
Simon Glass70cd0d72018-07-06 10:27:20 -0600336 def get_name(self, nodeoffset):
337 """Get the name of a node
338
339 Args:
340 nodeoffset: Offset of node to check
341
342 Returns:
343 Node name
344
345 Raises:
346 FdtException on error (e.g. nodeoffset is invalid)
347 """
348 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
349
Simon Glassa13d9022017-05-27 07:38:11 -0600350 def first_property_offset(self, nodeoffset, quiet=()):
351 """Get the offset of the first property in a node offset
352
353 Args:
354 nodeoffset: Offset to the node to check
355 quiet: Errors to ignore (empty to raise on all errors)
356
357 Returns:
358 Offset of the first property
359
360 Raises
361 FdtException if the associated node has no properties, or some
362 other error occurred
363 """
364 return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
365 quiet)
366
367 def next_property_offset(self, prop_offset, quiet=()):
368 """Get the next property in a node
369
370 Args:
371 prop_offset: Offset of the previous property
372 quiet: Errors to ignore (empty to raise on all errors)
373
374 Returns:
375 Offset of the next property
376
377 Raises:
378 FdtException if the associated node has no more properties, or
379 some other error occurred
380 """
381 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
382 quiet)
383
Simon Glassa13d9022017-05-27 07:38:11 -0600384 def get_property_by_offset(self, prop_offset, quiet=()):
385 """Obtains a property that can be examined
386
387 Args:
388 prop_offset: Offset of property (e.g. from first_property_offset())
389 quiet: Errors to ignore (empty to raise on all errors)
390
391 Returns:
392 Property object, or None if not found
393
394 Raises:
395 FdtException on error (e.g. invalid prop_offset or device
396 tree format)
397 """
398 pdata = check_err_null(
399 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
400 if isinstance(pdata, (int)):
401 return pdata
402 return Property(pdata[0], pdata[1])
403
Simon Glassb474c762018-07-26 14:02:13 -0600404 def getprop(self, nodeoffset, prop_name, quiet=()):
405 """Get a property from a node
Simon Glass0537c552018-07-06 10:27:22 -0600406
407 Args:
Simon Glassb474c762018-07-26 14:02:13 -0600408 nodeoffset: Node offset containing property to get
Simon Glass0537c552018-07-06 10:27:22 -0600409 prop_name: Name of property to get
410 quiet: Errors to ignore (empty to raise on all errors)
411
412 Returns:
Simon Glassb474c762018-07-26 14:02:13 -0600413 Value of property as a Property object (which can be used as a
414 bytearray/string), or -ve error number. On failure, returns an
415 integer error
Simon Glass0537c552018-07-06 10:27:22 -0600416
417 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600418 FdtError if any error occurs (e.g. the property is not found)
Simon Glass0537c552018-07-06 10:27:22 -0600419 """
Simon Glassb474c762018-07-26 14:02:13 -0600420 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
421 quiet)
Simon Glass0537c552018-07-06 10:27:22 -0600422 if isinstance(pdata, (int)):
423 return pdata
Simon Glassfd926662019-10-31 07:43:00 -0600424 return Property(prop_name, bytes(pdata[0]))
Simon Glassb474c762018-07-26 14:02:13 -0600425
426 def get_phandle(self, nodeoffset):
427 """Get the phandle of a node
428
429 Args:
430 nodeoffset: Node offset to check
431
432 Returns:
433 phandle of node, or 0 if the node has no phandle or another error
434 occurs
435 """
436 return fdt_get_phandle(self._fdt, nodeoffset)
437
Simon Glassfd926662019-10-31 07:43:00 -0600438 def get_alias(self, name):
439 """Get the full path referenced by a given alias
440
441 Args:
442 name: name of the alias to lookup
443
444 Returns:
445 Full path to the node for the alias named 'name', if it exists
446 None, if the given alias or the /aliases node does not exist
447 """
448 return fdt_get_alias(self._fdt, name)
449
Simon Glassb474c762018-07-26 14:02:13 -0600450 def parent_offset(self, nodeoffset, quiet=()):
451 """Get the offset of a node's parent
452
453 Args:
454 nodeoffset: Node offset to check
455 quiet: Errors to ignore (empty to raise on all errors)
456
457 Returns:
458 The offset of the parent node, if any
459
460 Raises:
461 FdtException if no parent found or other error occurs
462 """
463 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
464
465 def node_offset_by_phandle(self, phandle, quiet=()):
466 """Get the offset of a node with the given phandle
467
468 Args:
469 phandle: Phandle to search for
470 quiet: Errors to ignore (empty to raise on all errors)
471
472 Returns:
473 The offset of node with that phandle, if any
474
475 Raises:
476 FdtException if no node found or other error occurs
477 """
478 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
479
480
481class Fdt(FdtRo):
482 """Device tree class, supporting all operations
483
484 The Fdt object is created is created from a device tree binary file,
485 e.g. with something like:
486
487 fdt = Fdt(open("filename.dtb").read())
488
489 Operations can then be performed using the methods in this class. Each
490 method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
491
492 All methods raise an FdtException if an error occurs. To avoid this
493 behaviour a 'quiet' parameter is provided for some functions. This
494 defaults to empty, but you can pass a list of errors that you expect.
495 If one of these errors occurs, the function will return an error number
496 (e.g. -NOTFOUND).
497 """
498 def __init__(self, data):
499 FdtRo.__init__(self, data)
Simon Glass0537c552018-07-06 10:27:22 -0600500
Simon Glass70cd0d72018-07-06 10:27:20 -0600501 @staticmethod
502 def create_empty_tree(size, quiet=()):
503 """Create an empty device tree ready for use
Simon Glassa13d9022017-05-27 07:38:11 -0600504
505 Args:
Simon Glass70cd0d72018-07-06 10:27:20 -0600506 size: Size of device tree in bytes
Simon Glassa13d9022017-05-27 07:38:11 -0600507
508 Returns:
Simon Glass70cd0d72018-07-06 10:27:20 -0600509 Fdt object containing the device tree
Simon Glassa13d9022017-05-27 07:38:11 -0600510 """
Simon Glass70cd0d72018-07-06 10:27:20 -0600511 data = bytearray(size)
512 err = check_err(fdt_create_empty_tree(data, size), quiet)
513 if err:
514 return err
515 return Fdt(data)
Simon Glassa13d9022017-05-27 07:38:11 -0600516
Simon Glassb474c762018-07-26 14:02:13 -0600517 def resize(self, size, quiet=()):
Simon Glass70cd0d72018-07-06 10:27:20 -0600518 """Move the device tree into a larger or smaller space
Simon Glassa13d9022017-05-27 07:38:11 -0600519
Simon Glass70cd0d72018-07-06 10:27:20 -0600520 This creates a new device tree of size @size and moves the existing
521 device tree contents over to that. It can be used to create more space
Simon Glassb474c762018-07-26 14:02:13 -0600522 in a device tree. Note that the Fdt object remains the same, but it
523 now has a new bytearray holding the contents.
Simon Glassa13d9022017-05-27 07:38:11 -0600524
Simon Glass70cd0d72018-07-06 10:27:20 -0600525 Args:
526 size: Required new size of device tree in bytes
Simon Glassa13d9022017-05-27 07:38:11 -0600527 """
Simon Glass70cd0d72018-07-06 10:27:20 -0600528 fdt = bytearray(size)
Simon Glass70cd0d72018-07-06 10:27:20 -0600529 err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
530 if err:
531 return err
532 self._fdt = fdt
Simon Glassa13d9022017-05-27 07:38:11 -0600533
534 def pack(self, quiet=()):
535 """Pack the device tree to remove unused space
536
537 This adjusts the tree in place.
538
539 Args:
540 quiet: Errors to ignore (empty to raise on all errors)
541
Simon Glassb474c762018-07-26 14:02:13 -0600542 Returns:
543 Error code, or 0 if OK
544
Simon Glassa13d9022017-05-27 07:38:11 -0600545 Raises:
546 FdtException if any error occurs
547 """
Simon Glass04402d32018-07-06 10:27:21 -0600548 err = check_err(fdt_pack(self._fdt), quiet)
549 if err:
550 return err
551 del self._fdt[self.totalsize():]
552 return err
Simon Glassa13d9022017-05-27 07:38:11 -0600553
Simon Glass70cd0d72018-07-06 10:27:20 -0600554 def set_name(self, nodeoffset, name, quiet=()):
555 """Set the name of a node
556
557 Args:
558 nodeoffset: Node offset of node to update
Simon Glassb474c762018-07-26 14:02:13 -0600559 name: New node name (string without \0)
Simon Glass70cd0d72018-07-06 10:27:20 -0600560
561 Returns:
562 Error code, or 0 if OK
563
564 Raises:
565 FdtException if no parent found or other error occurs
566 """
Simon Glassb474c762018-07-26 14:02:13 -0600567 if chr(0) in name:
568 raise ValueError('Property contains embedded nul characters')
Simon Glass70cd0d72018-07-06 10:27:20 -0600569 return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
570
571 def setprop(self, nodeoffset, prop_name, val, quiet=()):
572 """Set the value of a property
573
574 Args:
575 nodeoffset: Node offset containing the property to create/update
576 prop_name: Name of property
577 val: Value to write (string or bytearray)
578 quiet: Errors to ignore (empty to raise on all errors)
579
580 Returns:
581 Error code, or 0 if OK
582
583 Raises:
584 FdtException if no parent found or other error occurs
585 """
586 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
587 len(val)), quiet)
588
589 def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
590 """Set the value of a property
591
592 Args:
593 nodeoffset: Node offset containing the property to create/update
594 prop_name: Name of property
595 val: Value to write (integer)
596 quiet: Errors to ignore (empty to raise on all errors)
597
598 Returns:
599 Error code, or 0 if OK
600
601 Raises:
602 FdtException if no parent found or other error occurs
603 """
604 return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
605 quiet)
606
607 def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
608 """Set the value of a property
609
610 Args:
611 nodeoffset: Node offset containing the property to create/update
612 prop_name: Name of property
613 val: Value to write (integer)
614 quiet: Errors to ignore (empty to raise on all errors)
615
616 Returns:
617 Error code, or 0 if OK
618
619 Raises:
620 FdtException if no parent found or other error occurs
621 """
622 return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
623 quiet)
624
625 def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
626 """Set the string value of a property
627
628 The property is set to the string, with a nul terminator added
629
630 Args:
631 nodeoffset: Node offset containing the property to create/update
632 prop_name: Name of property
Simon Glassb474c762018-07-26 14:02:13 -0600633 val: Value to write (string without nul terminator). Unicode is
634 supposed by encoding to UTF-8
Simon Glass70cd0d72018-07-06 10:27:20 -0600635 quiet: Errors to ignore (empty to raise on all errors)
636
637 Returns:
638 Error code, or 0 if OK
639
640 Raises:
641 FdtException if no parent found or other error occurs
642 """
Simon Glass7ccca832019-10-31 07:42:59 -0600643 val = val.encode('utf-8') + b'\0'
Simon Glass70cd0d72018-07-06 10:27:20 -0600644 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
645 val, len(val)), quiet)
646
Simon Glass5be24552018-09-14 04:57:06 -0600647 def delprop(self, nodeoffset, prop_name, quiet=()):
Simon Glass70cd0d72018-07-06 10:27:20 -0600648 """Delete a property from a node
649
650 Args:
651 nodeoffset: Node offset containing property to delete
652 prop_name: Name of property to delete
Simon Glass5be24552018-09-14 04:57:06 -0600653 quiet: Errors to ignore (empty to raise on all errors)
654
655 Returns:
656 Error code, or 0 if OK
Simon Glass70cd0d72018-07-06 10:27:20 -0600657
658 Raises:
659 FdtError if the property does not exist, or another error occurs
660 """
Simon Glass5be24552018-09-14 04:57:06 -0600661 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
662
663 def add_subnode(self, parentoffset, name, quiet=()):
664 """Add a new subnode to a node
665
666 Args:
667 parentoffset: Parent offset to add the subnode to
668 name: Name of node to add
669
670 Returns:
671 offset of the node created, or negative error code on failure
672
673 Raises:
674 FdtError if there is not enough space, or another error occurs
675 """
676 return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
Simon Glass70cd0d72018-07-06 10:27:20 -0600677
Simon Glass5be24552018-09-14 04:57:06 -0600678 def del_node(self, nodeoffset, quiet=()):
Simon Glass0537c552018-07-06 10:27:22 -0600679 """Delete a node
680
681 Args:
Simon Glass5be24552018-09-14 04:57:06 -0600682 nodeoffset: Offset of node to delete
683
684 Returns:
685 Error code, or 0 if OK
Simon Glass0537c552018-07-06 10:27:22 -0600686
687 Raises:
Simon Glass5be24552018-09-14 04:57:06 -0600688 FdtError if an error occurs
Simon Glass0537c552018-07-06 10:27:22 -0600689 """
Simon Glass5be24552018-09-14 04:57:06 -0600690 return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
Simon Glass0537c552018-07-06 10:27:22 -0600691
Simon Glass70cd0d72018-07-06 10:27:20 -0600692
693class Property(bytearray):
Simon Glassa13d9022017-05-27 07:38:11 -0600694 """Holds a device tree property name and value.
695
696 This holds a copy of a property taken from the device tree. It does not
697 reference the device tree, so if anything changes in the device tree,
698 a Property object will remain valid.
699
700 Properties:
701 name: Property name
Simon Glass70cd0d72018-07-06 10:27:20 -0600702 value: Property value as a bytearray
Simon Glassa13d9022017-05-27 07:38:11 -0600703 """
704 def __init__(self, name, value):
Simon Glass70cd0d72018-07-06 10:27:20 -0600705 bytearray.__init__(self, value)
Simon Glassa13d9022017-05-27 07:38:11 -0600706 self.name = name
Simon Glass70cd0d72018-07-06 10:27:20 -0600707
708 def as_cell(self, fmt):
709 return struct.unpack('>' + fmt, self)[0]
710
711 def as_uint32(self):
712 return self.as_cell('L')
713
714 def as_int32(self):
715 return self.as_cell('l')
716
717 def as_uint64(self):
718 return self.as_cell('Q')
719
720 def as_int64(self):
721 return self.as_cell('q')
722
723 def as_str(self):
Simon Glassb474c762018-07-26 14:02:13 -0600724 """Unicode is supported by decoding from UTF-8"""
725 if self[-1] != 0:
726 raise ValueError('Property lacks nul termination')
727 if 0 in self[:-1]:
728 raise ValueError('Property contains embedded nul characters')
729 return self[:-1].decode('utf-8')
Simon Glass70cd0d72018-07-06 10:27:20 -0600730
731
Simon Glassb474c762018-07-26 14:02:13 -0600732class FdtSw(FdtRo):
Simon Glass70cd0d72018-07-06 10:27:20 -0600733 """Software interface to create a device tree from scratch
734
735 The methods in this class work by adding to an existing 'partial' device
736 tree buffer of a fixed size created by instantiating this class. When the
Simon Glassb474c762018-07-26 14:02:13 -0600737 tree is complete, call as_fdt() to obtain a device tree ready to be used.
Simon Glass70cd0d72018-07-06 10:27:20 -0600738
739 Similarly with nodes, a new node is started with begin_node() and finished
740 with end_node().
741
742 The context manager functions can be used to make this a bit easier:
743
744 # First create the device tree with a node and property:
Simon Glassb474c762018-07-26 14:02:13 -0600745 sw = FdtSw()
Simon Glassfd926662019-10-31 07:43:00 -0600746 sw.finish_reservemap()
747 with sw.add_node(''):
748 with sw.add_node('node'):
749 sw.property_u32('reg', 2)
Simon Glassb474c762018-07-26 14:02:13 -0600750 fdt = sw.as_fdt()
Simon Glass70cd0d72018-07-06 10:27:20 -0600751
752 # Now we can use it as a real device tree
753 fdt.setprop_u32(0, 'reg', 3)
Simon Glassb474c762018-07-26 14:02:13 -0600754
755 The size hint provides a starting size for the space to be used by the
756 device tree. This will be increased automatically as needed as new items
757 are added to the tree.
Simon Glass70cd0d72018-07-06 10:27:20 -0600758 """
Simon Glassb474c762018-07-26 14:02:13 -0600759 INC_SIZE = 1024 # Expand size by this much when out of space
Simon Glass70cd0d72018-07-06 10:27:20 -0600760
Simon Glassb474c762018-07-26 14:02:13 -0600761 def __init__(self, size_hint=None):
762 """Create a new FdtSw object
Simon Glass70cd0d72018-07-06 10:27:20 -0600763
Simon Glassb474c762018-07-26 14:02:13 -0600764 Args:
765 size_hint: A hint as to the initial size to use
766
767 Raises:
768 ValueError if size_hint is negative
Simon Glass70cd0d72018-07-06 10:27:20 -0600769
Simon Glassb474c762018-07-26 14:02:13 -0600770 Returns:
771 FdtSw object on success, else integer error code (if not raising)
772 """
773 if not size_hint:
774 size_hint = self.INC_SIZE
775 fdtsw = bytearray(size_hint)
776 err = check_err(fdt_create(fdtsw, size_hint))
777 if err:
778 return err
779 self._fdt = fdtsw
780
781 def as_fdt(self):
Simon Glass70cd0d72018-07-06 10:27:20 -0600782 """Convert a FdtSw into an Fdt so it can be accessed as normal
783
Simon Glassb474c762018-07-26 14:02:13 -0600784 Creates a new Fdt object from the work-in-progress device tree. This
785 does not call fdt_finish() on the current object, so it is possible to
786 add more nodes/properties and call as_fdt() again to get an updated
787 tree.
Simon Glass70cd0d72018-07-06 10:27:20 -0600788
789 Returns:
790 Fdt object allowing access to the newly created device tree
791 """
Simon Glassb474c762018-07-26 14:02:13 -0600792 fdtsw = bytearray(self._fdt)
Simon Glass90ee4a72020-09-01 05:13:56 -0600793 while self.check_space(fdt_finish(fdtsw)):
794 fdtsw = bytearray(self._fdt)
Simon Glassb474c762018-07-26 14:02:13 -0600795 return Fdt(fdtsw)
Simon Glass70cd0d72018-07-06 10:27:20 -0600796
Simon Glassb474c762018-07-26 14:02:13 -0600797 def check_space(self, val):
798 """Check if we need to add more space to the FDT
799
800 This should be called with the error code from an operation. If this is
801 -NOSPACE then the FDT will be expanded to have more space, and True will
802 be returned, indicating that the operation needs to be tried again.
803
804 Args:
805 val: Return value from the operation that was attempted
806
807 Returns:
808 True if the operation must be retried, else False
809 """
810 if check_err(val, QUIET_NOSPACE) < 0:
811 self.resize(len(self._fdt) + self.INC_SIZE)
812 return True
813 return False
814
815 def resize(self, size):
Simon Glass70cd0d72018-07-06 10:27:20 -0600816 """Resize the buffer to accommodate a larger tree
817
818 Args:
819 size: New size of tree
Simon Glass70cd0d72018-07-06 10:27:20 -0600820
821 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600822 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600823 """
824 fdt = bytearray(size)
Simon Glassb474c762018-07-26 14:02:13 -0600825 err = check_err(fdt_resize(self._fdt, fdt, size))
826 self._fdt = fdt
Simon Glass70cd0d72018-07-06 10:27:20 -0600827
Simon Glassb474c762018-07-26 14:02:13 -0600828 def add_reservemap_entry(self, addr, size):
Simon Glass70cd0d72018-07-06 10:27:20 -0600829 """Add a new memory reserve map entry
830
831 Once finished adding, you must call finish_reservemap().
832
833 Args:
834 addr: 64-bit start address
835 size: 64-bit size
Simon Glass70cd0d72018-07-06 10:27:20 -0600836
837 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600838 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600839 """
Simon Glassb474c762018-07-26 14:02:13 -0600840 while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
841 size)):
842 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600843
Simon Glassb474c762018-07-26 14:02:13 -0600844 def finish_reservemap(self):
Simon Glass70cd0d72018-07-06 10:27:20 -0600845 """Indicate that there are no more reserve map entries to add
846
Simon Glass70cd0d72018-07-06 10:27:20 -0600847 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600848 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600849 """
Simon Glassb474c762018-07-26 14:02:13 -0600850 while self.check_space(fdt_finish_reservemap(self._fdt)):
851 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600852
Simon Glassb474c762018-07-26 14:02:13 -0600853 def begin_node(self, name):
Simon Glass70cd0d72018-07-06 10:27:20 -0600854 """Begin a new node
855
856 Use this before adding properties to the node. Then call end_node() to
857 finish it. You can also use the context manager as shown in the FdtSw
858 class comment.
859
860 Args:
861 name: Name of node to begin
Simon Glass70cd0d72018-07-06 10:27:20 -0600862
863 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600864 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600865 """
Simon Glassb474c762018-07-26 14:02:13 -0600866 while self.check_space(fdt_begin_node(self._fdt, name)):
867 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600868
Simon Glassb474c762018-07-26 14:02:13 -0600869 def property_string(self, name, string):
Simon Glass70cd0d72018-07-06 10:27:20 -0600870 """Add a property with a string value
871
872 The string will be nul-terminated when written to the device tree
873
874 Args:
875 name: Name of property to add
876 string: String value of property
Simon Glass70cd0d72018-07-06 10:27:20 -0600877
878 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600879 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600880 """
Simon Glassb474c762018-07-26 14:02:13 -0600881 while self.check_space(fdt_property_string(self._fdt, name, string)):
882 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600883
Simon Glassb474c762018-07-26 14:02:13 -0600884 def property_u32(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600885 """Add a property with a 32-bit value
886
887 Write a single-cell value to the device tree
888
889 Args:
890 name: Name of property to add
891 val: Value of property
Simon Glass70cd0d72018-07-06 10:27:20 -0600892
893 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600894 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600895 """
Simon Glassb474c762018-07-26 14:02:13 -0600896 while self.check_space(fdt_property_u32(self._fdt, name, val)):
897 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600898
Simon Glassb474c762018-07-26 14:02:13 -0600899 def property_u64(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600900 """Add a property with a 64-bit value
901
902 Write a double-cell value to the device tree in big-endian format
903
904 Args:
905 name: Name of property to add
906 val: Value of property
Simon Glass70cd0d72018-07-06 10:27:20 -0600907
908 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600909 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600910 """
Simon Glassb474c762018-07-26 14:02:13 -0600911 while self.check_space(fdt_property_u64(self._fdt, name, val)):
912 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600913
Simon Glassb474c762018-07-26 14:02:13 -0600914 def property_cell(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600915 """Add a property with a single-cell value
916
917 Write a single-cell value to the device tree
918
919 Args:
920 name: Name of property to add
921 val: Value of property
922 quiet: Errors to ignore (empty to raise on all errors)
923
924 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600925 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600926 """
Simon Glassb474c762018-07-26 14:02:13 -0600927 while self.check_space(fdt_property_cell(self._fdt, name, val)):
928 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600929
Simon Glassb474c762018-07-26 14:02:13 -0600930 def property(self, name, val):
Simon Glass70cd0d72018-07-06 10:27:20 -0600931 """Add a property
932
933 Write a new property with the given value to the device tree. The value
934 is taken as is and is not nul-terminated
935
936 Args:
937 name: Name of property to add
938 val: Value of property
939 quiet: Errors to ignore (empty to raise on all errors)
940
941 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600942 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600943 """
Simon Glassb474c762018-07-26 14:02:13 -0600944 while self.check_space(fdt_property_stub(self._fdt, name, val,
945 len(val))):
946 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600947
Simon Glassb474c762018-07-26 14:02:13 -0600948 def end_node(self):
Simon Glass70cd0d72018-07-06 10:27:20 -0600949 """End a node
950
951 Use this after adding properties to a node to close it off. You can also
952 use the context manager as shown in the FdtSw class comment.
953
954 Args:
955 quiet: Errors to ignore (empty to raise on all errors)
956
957 Raises:
Simon Glassb474c762018-07-26 14:02:13 -0600958 FdtException on any error
Simon Glass70cd0d72018-07-06 10:27:20 -0600959 """
Simon Glassb474c762018-07-26 14:02:13 -0600960 while self.check_space(fdt_end_node(self._fdt)):
961 pass
Simon Glass70cd0d72018-07-06 10:27:20 -0600962
Simon Glassb474c762018-07-26 14:02:13 -0600963 def add_node(self, name):
Simon Glass70cd0d72018-07-06 10:27:20 -0600964 """Create a new context for adding a node
965
966 When used in a 'with' clause this starts a new node and finishes it
967 afterward.
968
969 Args:
970 name: Name of node to add
971 """
Simon Glassb474c762018-07-26 14:02:13 -0600972 return NodeAdder(self, name)
Simon Glass70cd0d72018-07-06 10:27:20 -0600973
974
975class NodeAdder():
976 """Class to provide a node context
977
978 This allows you to add nodes in a more natural way:
979
Simon Glassb474c762018-07-26 14:02:13 -0600980 with fdtsw.add_node('name'):
Simon Glass70cd0d72018-07-06 10:27:20 -0600981 fdtsw.property_string('test', 'value')
982
983 The node is automatically completed with a call to end_node() when the
984 context exits.
985 """
Simon Glassb474c762018-07-26 14:02:13 -0600986 def __init__(self, fdtsw, name):
987 self._fdt = fdtsw
Simon Glass70cd0d72018-07-06 10:27:20 -0600988 self._name = name
989
990 def __enter__(self):
Simon Glassb474c762018-07-26 14:02:13 -0600991 self._fdt.begin_node(self._name)
Simon Glass70cd0d72018-07-06 10:27:20 -0600992
993 def __exit__(self, type, value, traceback):
Simon Glassb474c762018-07-26 14:02:13 -0600994 self._fdt.end_node()
Simon Glassa13d9022017-05-27 07:38:11 -0600995%}
996
997%rename(fdt_property) fdt_property_func;
998
Simon Glassb474c762018-07-26 14:02:13 -0600999/*
1000 * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
1001 * so use the same type here.
1002 */
1003typedef uint32_t fdt32_t;
Simon Glassa13d9022017-05-27 07:38:11 -06001004
1005%include "libfdt/fdt.h"
1006
1007%include "typemaps.i"
1008
1009/* Most functions don't change the device tree, so use a const void * */
1010%typemap(in) (const void *)(const void *fdt) {
1011 if (!PyByteArray_Check($input)) {
1012 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1013 "', argument " "$argnum"" of type '" "$type""'");
1014 }
1015 $1 = (void *)PyByteArray_AsString($input);
1016 fdt = $1;
Tom Rini65b0dea2021-05-24 11:47:01 -04001017 (void)fdt; /* avoid unused variable warning */
Simon Glassa13d9022017-05-27 07:38:11 -06001018}
1019
1020/* Some functions do change the device tree, so use void * */
1021%typemap(in) (void *)(const void *fdt) {
1022 if (!PyByteArray_Check($input)) {
1023 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1024 "', argument " "$argnum"" of type '" "$type""'");
1025 }
1026 $1 = PyByteArray_AsString($input);
1027 fdt = $1;
Tom Rini65b0dea2021-05-24 11:47:01 -04001028 (void)fdt; /* avoid unused variable warning */
Simon Glassa13d9022017-05-27 07:38:11 -06001029}
1030
Simon Glass70cd0d72018-07-06 10:27:20 -06001031/* typemap used for fdt_get_property_by_offset() */
Simon Glassa13d9022017-05-27 07:38:11 -06001032%typemap(out) (struct fdt_property *) {
1033 PyObject *buff;
1034
1035 if ($1) {
1036 resultobj = PyString_FromString(
1037 fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
1038 buff = PyByteArray_FromStringAndSize(
1039 (const char *)($1 + 1), fdt32_to_cpu($1->len));
1040 resultobj = SWIG_Python_AppendOutput(resultobj, buff);
1041 }
1042}
1043
1044%apply int *OUTPUT { int *lenp };
1045
1046/* typemap used for fdt_getprop() */
1047%typemap(out) (const void *) {
1048 if (!$1)
1049 $result = Py_None;
1050 else
Simon Glassfd926662019-10-31 07:43:00 -06001051 %#if PY_VERSION_HEX >= 0x03000000
1052 $result = Py_BuildValue("y#", $1, *arg4);
1053 %#else
1054 $result = Py_BuildValue("s#", $1, *arg4);
1055 %#endif
Simon Glassa13d9022017-05-27 07:38:11 -06001056}
1057
Simon Glass70cd0d72018-07-06 10:27:20 -06001058/* typemap used for fdt_setprop() */
1059%typemap(in) (const void *val) {
Simon Glassfd926662019-10-31 07:43:00 -06001060 %#if PY_VERSION_HEX >= 0x03000000
1061 if (!PyBytes_Check($input)) {
1062 SWIG_exception_fail(SWIG_TypeError, "bytes expected in method '" "$symname"
1063 "', argument " "$argnum"" of type '" "$type""'");
1064 }
1065 $1 = PyBytes_AsString($input);
1066 %#else
1067 $1 = PyString_AsString($input); /* char *str */
1068 %#endif
Simon Glass70cd0d72018-07-06 10:27:20 -06001069}
1070
Simon Glass70cd0d72018-07-06 10:27:20 -06001071/* typemaps used for fdt_next_node() */
1072%typemap(in, numinputs=1) int *depth (int depth) {
1073 depth = (int) PyInt_AsLong($input);
1074 $1 = &depth;
1075}
1076
1077%typemap(argout) int *depth {
1078 PyObject *val = Py_BuildValue("i", *arg$argnum);
1079 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1080}
1081
1082%apply int *depth { int *depth };
1083
1084/* typemaps for fdt_get_mem_rsv */
1085%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
1086 $1 = &temp;
1087}
1088
1089%typemap(argout) uint64_t * {
Simon Glassfd926662019-10-31 07:43:00 -06001090 PyObject *val = PyLong_FromUnsignedLongLong(*arg$argnum);
Simon Glass70cd0d72018-07-06 10:27:20 -06001091 if (!result) {
1092 if (PyTuple_GET_SIZE(resultobj) == 0)
1093 resultobj = val;
1094 else
1095 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1096 }
1097}
1098
Simon Glassa13d9022017-05-27 07:38:11 -06001099/* We have both struct fdt_property and a function fdt_property() */
1100%warnfilter(302) fdt_property;
1101
1102/* These are macros in the header so have to be redefined here */
Simon Glassb474c762018-07-26 14:02:13 -06001103uint32_t fdt_magic(const void *fdt);
1104uint32_t fdt_totalsize(const void *fdt);
1105uint32_t fdt_off_dt_struct(const void *fdt);
1106uint32_t fdt_off_dt_strings(const void *fdt);
1107uint32_t fdt_off_mem_rsvmap(const void *fdt);
1108uint32_t fdt_version(const void *fdt);
1109uint32_t fdt_last_comp_version(const void *fdt);
1110uint32_t fdt_boot_cpuid_phys(const void *fdt);
1111uint32_t fdt_size_dt_strings(const void *fdt);
1112uint32_t fdt_size_dt_struct(const void *fdt);
1113
Simon Glass70cd0d72018-07-06 10:27:20 -06001114int fdt_property_string(void *fdt, const char *name, const char *val);
1115int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1116
1117/*
1118 * This function has a stub since the name fdt_property is used for both a
1119 * function and a struct, which confuses SWIG.
1120 */
Simon Glassc5db5192019-10-31 07:43:01 -06001121int fdt_property_stub(void *fdt, const char *name, const void *val, int len);
Simon Glassa13d9022017-05-27 07:38:11 -06001122
1123%include <../libfdt/libfdt.h>